package com.glodon.paas.search.listener.impl;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import jsonij.json.JPath;
import jsonij.json.Value;

import org.apache.commons.beanutils.BeanUtils;
import org.dozer.Mapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;

import com.glodon.paas.databag.api.bean.DatabagDto;
import com.glodon.paas.document.api.bean.File;
import com.glodon.paas.search.index.IndexService;
import com.glodon.paas.search.listener.IndexListener;
import com.glodon.paas.search.model.DatabagEvent;
import com.glodon.paas.search.model.Event;
import com.glodon.paas.search.model.EventType;
import com.glodon.paas.search.model.IndexBase;
import com.glodon.paas.search.model.IndexDocument;
import com.glodon.paas.search.model.IndexRevitStructure;
import com.glodon.paas.search.parser.TextParseFactory;
import com.glodon.paas.search.parser.TextParser;
import com.glodon.paas.search.util.DatabagWebService;
import com.glodon.paas.search.util.DocWebService;
import com.glodon.paas.search.util.SearchConstants;

@Component("databagListener")
public class DatabagListenerImpl implements IndexListener {
    private Logger logger = LoggerFactory.getLogger(DatabagListenerImpl.class);
    @Autowired
    private DatabagWebService databagWebService;
    @Autowired
    private IndexService indexService;
    @Autowired
    private DocWebService docWebService;
    @Autowired
    private TextParseFactory textParseFactory;
    @Autowired
    private Mapper dozerMapper;

    private TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("databag-index");

    @Override
    public void onEvent(final Event event) {
        if (!(event instanceof DatabagEvent)) {
            logger.warn("event is not DatabagEvent Class type.");
            return;
        }
        taskExecutor.execute(new Runnable() {
            @Override
            public void run() {
                DatabagEvent dEvent = (DatabagEvent) event;
                String databagId = dEvent.getDatabagId();
                DatabagDto databag = databagWebService.getDatabag(databagId);
                if (EventType.UPLOAD.equals(dEvent.getEventType())) {
                    doIndexing(databag);
                } else if (EventType.DELETE.equals(dEvent.getEventType())) {
                    doDeleteIndex(databag);
                }
            }
        });
    };

    @SuppressWarnings("rawtypes")
    private void doIndexing(DatabagDto databag) {
        File file = docWebService.getFileMeta(databag.getFileId(), databag.getUserId());
        String type = databag.getType();
        IndexBase indexBase = null;
        if ("doc".equals(type)) {
            indexBase = dozerMapper.map(file, IndexDocument.class);
            indexBase.setDatabagId(databag.getId());
            indexBase.setName(file.getName() + "." + file.getExtension());
        } else if ("rvt".equals(type)) {
            indexBase = dozerMapper.map(file, IndexRevitStructure.class);
            indexBase.setDatabagId(databag.getId());
            indexBase.setName(file.getName() + "." + file.getExtension());
        } else {
            return;
        }
        // 第一步，读取manifest文件
        String manifest = databagWebService.getManifest(databag.getId());
        // 第二步，解析出properties文件
        List<String> files = parseIndexingFile(manifest);
        // 第三步，索引properties文件
        for (Iterator<String> iterator = files.iterator(); iterator.hasNext();) {
            String propFile = iterator.next();
            InputStream is = databagWebService.downloadResource(databag.getId(), propFile);
            TextParser textParser = textParseFactory.getTextParser(type);
            List<Map> parsedTextMap = textParser.parse(is);
            for (Map textMap : parsedTextMap) {
                try {
                    BeanUtils.populate(indexBase, textMap);
                } catch (Exception e) {
                    logger.error("failed to populate indexBase: " + textMap, e);
                    continue;
                }
                if ("doc".equals(type)) {
                    indexService.index(SearchConstants.INDEX_PAAS, SearchConstants.TYPE_DOC, indexBase);
                } else if ("rvt".equals(type)) {
                    indexService.index(SearchConstants.INDEX_PAAS, SearchConstants.TYPE_RVT, indexBase);
                } else {
                    return;
                }
            }
        }
    }

    private void doDeleteIndex(DatabagDto databag) {
        indexService.delete(SearchConstants.INDEX_PAAS, databag.getType(), databag.getFileId());
    }

    /**
     * 从manifest文件中解析出properties文件.
     * 
     * @param manifest
     * @return pdf文件列表
     */
    private List<String> parseIndexingFile(String manifest) {
        List<String> files = new ArrayList<String>();
        try {
            Value content = JPath.evaluate(manifest, "/Metadata/TextContent");
            if (content != null) {
                String text = content.getString();
                files.add(text);
                return files;
            }
        } catch (Exception e) {
            logger.error("failed to parse out text from manifest.json in /Metadata/TextContent.", e);
        }
        try {
            Value prop = JPath.evaluate(manifest, "/Metadata/Properties");
            if (prop != null) {
                String properties = prop.getString();
                files.add(properties);
            }
        } catch (Exception e) {
            logger.error("failed to parse out text from manifest.json in /Metadata/Properties", e);
        }
        return files;
    }

    public void setDocWebService(DocWebService docWebService) {
        this.docWebService = docWebService;
    }

    public void setDatabagWebService(DatabagWebService databagWebService) {
        this.databagWebService = databagWebService;
    }

    public void setIndexService(IndexService indexService) {
        this.indexService = indexService;
    }
}
